package web_api

import (
	"bufio"
	"encoding/json"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"gitee.com/rw555/fdsmastergo/pkg/logger"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// LogEntry 表示一条日志记录
type LogEntry struct {
	Time      string                 `json:"time"`
	Level     string                 `json:"level"`
	Message   string                 `json:"message"`
	Category  string                 `json:"category,omitempty"`
	Service   string                 `json:"service,omitempty"`
	Details   map[string]interface{} `json:"details,omitempty"`
	Source    string                 `json:"source,omitempty"`
	Timestamp int64                  `json:"timestamp"`
}

// LogFilter 日志过滤条件
type LogFilter struct {
	Level      string `json:"level" form:"level"`           // 日志级别
	Service    string `json:"service" form:"service"`       // 服务名称
	Category   string `json:"category" form:"category"`     // 日志类别
	SearchTerm string `json:"search" form:"search"`         // 搜索关键词
	Date       string `json:"date" form:"date"`             // 日期过滤
	StartTime  string `json:"start_time" form:"start_time"` // 开始时间
	EndTime    string `json:"end_time" form:"end_time"`     // 结束时间
	Page       int    `json:"page" form:"page"`             // 页码
	PageSize   int    `json:"page_size" form:"page_size"`   // 每页条数
}

// LogResponse 日志响应结构
type LogResponse struct {
	Total int        `json:"total"`
	Logs  []LogEntry `json:"logs"`
	Page  int        `json:"page"`
	Pages int        `json:"pages"`
}

// HandleGetLogs 处理获取日志请求
func (h *Handler) HandleGetLogs(c *gin.Context) {
	var filter LogFilter

	// 尝试从POST请求体中绑定JSON参数
	if c.Request.Method == "POST" && c.Request.ContentLength > 0 {
		if err := c.ShouldBindJSON(&filter); err != nil {
			logger.SystemError("绑定JSON参数失败", zap.Error(err))
			// 即使绑定失败，我们也继续处理，使用默认值或查询参数
		}
	}

	// 如果POST请求体中没有参数，或者是GET请求，则尝试从查询参数中绑定
	if (c.Request.Method == "POST" && c.Request.ContentLength == 0) || c.Request.Method == "GET" {
		if err := c.ShouldBindQuery(&filter); err != nil {
			logger.SystemError("绑定查询参数失败", zap.Error(err))
			// 即使绑定失败，我们也继续处理，使用默认值
		}
	}

	// 设置默认值
	if filter.Page <= 0 {
		filter.Page = 1
	}
	if filter.PageSize <= 0 {
		filter.PageSize = 20
	}

	// 获取日志类型
	logType := c.Param("type")
	if logType == "" {
		logType = "system" // 默认为系统日志
	}

	logger.SystemInfo("获取日志请求",
		zap.String("type", logType), // 这是URL路径中的日志类型参数
		zap.String("level", filter.Level),
		zap.String("service", filter.Service),
		zap.String("sub_category", filter.Category), // 重命名为sub_category以避免混淆
		zap.String("search", filter.SearchTerm),
		zap.String("date", filter.Date),
		zap.Int("page", filter.Page),
		zap.Int("page_size", filter.PageSize))

	// 记录请求体内容，便于调试
	if c.Request.Method == "POST" && c.Request.ContentLength > 0 {
		var requestBody map[string]interface{}
		if err := c.ShouldBindJSON(&requestBody); err == nil {
			jsonBytes, _ := json.Marshal(requestBody)
			logger.SystemDebug("请求体内容", zap.String("body", string(jsonBytes)))
		}
	}

	// 获取日志文件路径
	logFile := getLogFilePath(logType)
	if logFile == "" {
		logger.SystemWarn("未找到日志文件", zap.String("type", logType))
		// 如果找不到日志文件，返回空结果而不是错误
		c.JSON(http.StatusOK, LogResponse{
			Total: 0,
			Logs:  []LogEntry{},
			Page:  filter.Page,
			Pages: 0,
		})
		return
	}

	// 读取并过滤日志
	logs, err := readAndFilterLogs(logFile, filter)
	if err != nil {
		logger.SystemError("读取日志文件失败", zap.String("file", logFile), zap.Error(err))
		c.JSON(http.StatusInternalServerError, gin.H{"error": "读取日志失败"})
		return
	}

	// 计算总页数
	totalPages := (len(logs) + filter.PageSize - 1) / filter.PageSize

	// 分页
	startIndex := (filter.Page - 1) * filter.PageSize
	endIndex := startIndex + filter.PageSize
	if endIndex > len(logs) {
		endIndex = len(logs)
	}

	// 如果起始索引超出范围，返回空结果
	if startIndex >= len(logs) && len(logs) > 0 {
		c.JSON(http.StatusOK, LogResponse{
			Total: len(logs),
			Logs:  []LogEntry{},
			Page:  filter.Page,
			Pages: totalPages,
		})
		return
	}

	var pagedLogs []LogEntry
	if len(logs) > 0 {
		pagedLogs = logs[startIndex:endIndex]
	} else {
		pagedLogs = []LogEntry{}
	}

	c.JSON(http.StatusOK, LogResponse{
		Total: len(logs),
		Logs:  pagedLogs,
		Page:  filter.Page,
		Pages: totalPages,
	})
}

// getLogFilePath 根据日志类型获取日志文件路径
func getLogFilePath(logType string) string {
	// 获取日志根目录
	logRootDir := logger.LogRootDir
	if logRootDir == "" {
		// 如果未设置，尝试从可执行文件路径推断
		exePath, err := os.Executable()
		if err != nil {
			logger.SystemError("获取可执行文件路径失败", zap.Error(err))
			return ""
		}
		// 获取cmd目录（可执行文件所在目录的上级：bin -> xxx_server -> cmd）
		logRootDir = filepath.Join(filepath.Dir(filepath.Dir(filepath.Dir(exePath))), "logs")
		logger.SystemInfo("推断日志根目录", zap.String("logRootDir", logRootDir))
	}

	// 映射日志类型到文件名
	var fileName string
	switch logType {
	case "system":
		fileName = "system.log"
	case "operation":
		fileName = "operation.log"
	case "network":
		fileName = "network.log"
	case "other":
		fileName = "other.log"
	case "error":
		fileName = "error.log"
	default:
		logger.SystemWarn("无效的日志类型", zap.String("type", logType))
		return ""
	}

	// 遍历所有服务目录，查找日志文件
	entries, err := os.ReadDir(logRootDir)
	if err != nil {
		logger.SystemError("读取日志根目录失败", zap.String("dir", logRootDir), zap.Error(err))
		return ""
	}

	// 首先尝试查找web_server目录下的日志
	for _, entry := range entries {
		if entry.IsDir() && entry.Name() == "web_server" {
			logPath := filepath.Join(logRootDir, entry.Name(), fileName)
			if _, err := os.Stat(logPath); err == nil {
				logger.SystemInfo("找到日志文件", zap.String("path", logPath))
				return logPath
			}
		}
	}

	// 如果web_server目录下没有找到，则查找其他目录
	for _, entry := range entries {
		if entry.IsDir() {
			logPath := filepath.Join(logRootDir, entry.Name(), fileName)
			if _, err := os.Stat(logPath); err == nil {
				logger.SystemInfo("找到日志文件", zap.String("path", logPath))
				return logPath
			}
		}
	}

	logger.SystemWarn("未找到日志文件", zap.String("type", logType), zap.String("fileName", fileName))
	return ""
}

// readAndFilterLogs 读取并过滤日志
func readAndFilterLogs(filePath string, filter LogFilter) ([]LogEntry, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var logs []LogEntry
	scanner := bufio.NewScanner(file)

	// 解析日期过滤条件
	var filterDate time.Time
	if filter.Date != "" {
		filterDate, _ = time.Parse("2006-01-02", filter.Date)
	}

	for scanner.Scan() {
		line := scanner.Text()
		if line == "" {
			continue
		}

		var entry map[string]interface{}
		if err := json.Unmarshal([]byte(line), &entry); err != nil {
			// 如果解析失败，跳过这一行
			continue
		}

		// 提取基本字段
		logEntry := LogEntry{
			Details: make(map[string]interface{}),
		}

		// 提取时间
		if timeStr, ok := entry["T"].(string); ok {
			// 尝试解析时间格式
			if t, err := time.Parse("20060102150405", timeStr); err == nil {
				logEntry.Time = t.Format("2006-01-02 15:04:05")
				logEntry.Timestamp = t.Unix()

				// 日期过滤
				if !filterDate.IsZero() {
					logDate := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
					filterDateOnly := time.Date(filterDate.Year(), filterDate.Month(), filterDate.Day(), 0, 0, 0, 0, filterDate.Location())
					if !logDate.Equal(filterDateOnly) {
						continue
					}
				}
			} else {
				logEntry.Time = timeStr
			}
		}

		// 提取级别
		if level, ok := entry["L"].(string); ok {
			logEntry.Level = level
			// 级别过滤
			if filter.Level != "" && filter.Level != "all" && !strings.EqualFold(level, filter.Level) {
				continue
			}
		}

		// 提取消息
		if msg, ok := entry["M"].(string); ok {
			logEntry.Message = msg
			// 关键词过滤
			if filter.SearchTerm != "" && !strings.Contains(strings.ToLower(msg), strings.ToLower(filter.SearchTerm)) {
				continue
			}
		}

		// 提取分类
		if category, ok := entry["category"].(string); ok {
			logEntry.Category = category
			// 分类过滤
			if filter.Category != "" && filter.Category != "all" && category != filter.Category {
				continue
			}
		}

		// 提取服务名称（从调用者信息或其他字段推断）
		if caller, ok := entry["C"].(string); ok {
			parts := strings.Split(caller, "/")
			if len(parts) > 0 {
				for _, part := range parts {
					if strings.Contains(part, "_server") {
						logEntry.Service = strings.TrimSuffix(part, "_server")
						break
					}
				}
			}
		}

		// 如果从调用者信息中没有找到服务名称，尝试从日志文件路径推断
		if logEntry.Service == "" {
			// 从文件路径中提取服务名称
			pathParts := strings.Split(filePath, string(os.PathSeparator))
			for _, part := range pathParts {
				if strings.Contains(part, "_server") {
					logEntry.Service = strings.TrimSuffix(part, "_server")
					break
				}
			}
		}

		// 如果仍然没有找到服务名称，使用默认值
		if logEntry.Service == "" {
			logEntry.Service = "web" // 默认为web服务
		}

		// 将服务名称首字母大写
		logEntry.Service = strings.Title(logEntry.Service)

		// 服务过滤
		if filter.Service != "" && filter.Service != "all" {
			if !strings.Contains(logEntry.Service, filter.Service) {
				continue
			}
		}

		// 提取其他字段作为详情
		for k, v := range entry {
			if k != "T" && k != "L" && k != "M" && k != "C" && k != "category" {
				logEntry.Details[k] = v
			}
		}

		// 设置来源
		logEntry.Source = filepath.Base(filePath)

		logs = append(logs, logEntry)
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	// 按时间戳倒序排序（最新的日志在前面）
	// 这里简单实现，实际可能需要更高效的排序
	for i := 0; i < len(logs)-1; i++ {
		for j := i + 1; j < len(logs); j++ {
			if logs[i].Timestamp < logs[j].Timestamp {
				logs[i], logs[j] = logs[j], logs[i]
			}
		}
	}

	return logs, nil
}
